/**
*
* @author Anastasiya
*
* Ozawa algorithm realization
*
*/

#pragma once
#include "printing.h"
#include <ogdf/basic/Graph.h>
#include <ogdf/basic/NodeArray.h>
#include <ogdf/internal/planarity/PlanarSubgraphPQTree.h>
#include <ogdf/internal/planarity/PlanarPQTree.h>
#include <map>
#include <exception>

typedef ogdf::PlanarLeafKey<ogdf::whaInfo*> PlanarPQTreeLeaf;
typedef ogdf::SListPure<PlanarPQTreeLeaf*> PQTreeLeavesList;
typedef ogdf::NodeArray<int> STNumbering;
typedef std::map<ogdf::node, PQTreeLeavesList*> NodesToPQLeavesMap;

class OzawaResultHandler{
public: virtual void resultProcessionFunction(const std::string, const ogdf::Graph*, const int, const ULONGLONG) const = 0;
		virtual void errorProcessionFunction(const std::string, const std::string) const = 0;
};

class OzawaException: public std::exception
{
public: OzawaException(std::string message);
		std::string message;
};


class OzawaAlgorithm{
public: static void execute(const std::string inputFileName, const OzawaResultHandler* resultHandler, 
			const Printer* printer);
		static std::string getName();

private: const Printer* printer;
		 ogdf::PlanarSubgraphPQTree tree;
		 ogdf::SList<ogdf::PQLeafKey<ogdf::edge, ogdf::whaInfo*, bool>*> edgesToDelete;
		 ogdf::Graph* graph;
		 SYSTEMTIME startTime;
		 SYSTEMTIME endTime;
		 NodesToPQLeavesMap allPQTreeLeaves;
		 NodesToPQLeavesMap reducingPQTreeLeaves;

		 OzawaAlgorithm(const ogdf::Graph& graph, const Printer* printer);
		 ~OzawaAlgorithm();
		 ULONGLONG getExecutionTime() const;
		 int getDeletedEdgesCount() const;
		 const ogdf::Graph* getGraph() const;
		 void execute();

		 void computeStNumbering(STNumbering* stNumbering);
		 void computePQTreeLeaves(const STNumbering* stNumbering, NodesToPQLeavesMap* leafsMap, 
			 ogdf::Array<ogdf::node>* stNumberedNodes);
		 static PQTreeLeavesList* computePQTreeLeaves(const ogdf::node* n, const STNumbering* stNumbering);
		 void computeLeavesForReduce(NodesToPQLeavesMap* treeLeavesMap, NodesToPQLeavesMap* reduceLeavesMap);
		 void deleteComputedEdgesFromGraph() const;
		 void assertAlgorithmApplicable() const;
		 void buildAndReduceTree(NodesToPQLeavesMap* allPQTreeLeaves, 
			 NodesToPQLeavesMap* reducingPQTreeLeaves, 
			 const ogdf::Array<ogdf::node>* stNumberedNodes);
		 void makeNextReduceStep(PQTreeLeavesList* leaves, PQTreeLeavesList* reduceLeaves);
		 void logReducingStep(int stepNumber) const;
		 static void cleanMap(NodesToPQLeavesMap* map);

		 static const std::string ALGORITHM_NAME;
};